package it.tukano.treditor.engine.geom;

import java.io.Serializable;

/**
 * An euler angles set. Immutable.
 * @author pgi
 */
public final class EulerSet implements Serializable {
    
    /* default serial version uid*/
    private static final long serialVersionUID = 0;
    
    /* The angles in radians, along the three axes */
    private final Number
            radx,
            rady,
            radz;
    
    /* True if this euler set is in radians, false if it is in degrees */
    private final boolean radians;

    /**
     * Instance initializer
     */
    public EulerSet() {
        this(0, 0, 0, true);
    }
    
    /**
     * Instance initializer
     * @param x the x angle
     * @param y the y angle
     * @param z the z angle
     * @param radians true if x,y,z are in radians, false if in degrees
     */
    public EulerSet(Number x, Number y, Number z, boolean radians) {
        if(radians) {
            radx = x;
            rady = y;
            radz = z;
        } else {
            radx = Math.toRadians(x.doubleValue());
            rady = Math.toRadians(y.doubleValue());
            radz = Math.toRadians(z.doubleValue());
        }
        this.radians = radians;
    }
    
    /**
     * Returns a euler set in degrees
     * @return this euler values set in degrees
     */
    public EulerSet toDegrees() {
        return isDegrees() ?
                this :
                new EulerSet(radx, rady, radz, false);
    }
    
    /**
     * Returns a euler set in radians
     * @return this euler values set in radians
     */
    public EulerSet toRadians() {
        return isRadians() ?
                this :
                new EulerSet(radx, rady, radz, true);
    }
    
    /**
     * Returns the x angle
     * @return the x angle, in radians or degrees depending on the value of
     * isRadians()
     */
    public Number getX() {
        return radians ? radx : Math.toDegrees(radx.doubleValue());
    }
    
    /**
     * Returns the y angle
     * @return the y angle, in radians or degrees, depending on the value of
     * isRadians()
     */
    public Number getY() {
        return radians ? rady : Math.toDegrees(rady.doubleValue());
    }
    
    /**
     * Returns the z angle
     * @return the z angle, in radians or degrees, depending on the value of
     * isRadians()
     */
    public Number getZ() {
        return radians ? radz : Math.toDegrees(radz.doubleValue());
    }
    
    /**
     * Checks if this euler set is in radians
     * @return true if the angles are in radians
     */
    public boolean isRadians() {
        return radians;
    }
    
    /**
     * Checks if this euler set is in degrees
     * @return true if the angles are in degrees
     */
    public boolean isDegrees() {
        return !radians;
    }
    
    public static EulerSet newDegreesInstance(Number x, Number y, Number z) {
        return new EulerSet(x, y, z, false);
    }
    
    public static EulerSet newRadiansInstance(Number x, Number y, Number z) {
        return new EulerSet(x, y, z, true);
    }
}
